/**
	futher encapsulation ftp regular operation
	author yeqin
	date:2022-04-08

*/

const fs = require('fs')
const util = require('util');
const stat = util.promisify(fs.stat)

class FtpOperate {

	//ftp client 
	client;

	constructor(client){
		this.client = client;
	}

	/**
		list information about the specified directory.
		return a list of file name.
		(String) => [String]
	*/
	async list(filePath=""){
		return await this.cmd('list',[filePath])
	}


	/**
		go to the specified directory.
	*/
	async cwd(filePath=""){
		return await this.cmd('cwd',[filePath])
	}


	/**
		create directory
		(String,Boolean) => Promise
		filepath: directory path
		recursive: whether to allow recursive directory creation.
	*/
	async mkdir(filePath,recursive=false){
		return await this.cmd('mkdir',[filePath,recursive])
	}


	async mkdirAndGoto(filePath){
		await this.mkdir(filePath)
		await this.cwd(filePath)
	}

	
	/**
		upload file to host.
		(String,String) => Promise({spentTime:Number,speed:Number})
		localFilePath: local file absolute path.
		desFileName:  file name relative path.  (upload file path usage ftp current path)
		example: put('D://a.text','a.text')
	*/
	async put(localFilePath,desFileName,config){
		const startTime = new Date().getTime()
		await this.cmd('put',[localFilePath,desFileName],config)
		const overTime = new Date().getTime()
		const userSeconds = (overTime - startTime)/1000
		const fileStat = await stat(localFilePath);
		const speendForSecond = fileStat.size/1000/userSeconds;
		return {
					size:fileStat.size,
					spentTime:Math.max(userSeconds.toFixed(2),0.01),
					speed:Math.max(speendForSecond.toFixed(2),0.01)
				}
	}


	/**
		remove file 
	*/
	async delete(filename){
		return await this.cmd('delete',[filename])
	}

	/**
		remove directory 
	*/
	async rmdir(dir,recursive=true){
		return await this.cmd('rmdir',[dir,recursive])
	}

	async logout(){
		return await this.cmd('logout',[])
	}

	/**
		a unified calling method.
		convert callback methods of the client to asynchronous methods.
		(String,[Object]) => Promise<Object>
	*/
	cmd(method,param,config={}){

		const {outTime} = config;

		return new Promise( (resolve,reject) => {

			let isInvoke = false;

			if(outTime){
				setTimeout(()=>{
					if(!isInvoke){
						isInvoke = true;
						reject('FTP_OUT_TIME')
					}
				},outTime)
			}


			const callback = (err,data) => {

				//if outTime
				if(isInvoke)
					return;

				if(err){
					return reject(err)
				}
				resolve(data)
			};

			this.client[method].apply(this.client,[...param,callback])	

		})
	}



}


module.exports = {FtpOperate}